#ifndef DEVICE_H
#define DEVICE_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDateTime>
#include <QTimer>
#include <QList>
#include <QQueue>

#include "types.h"
#include "task.h"
#include "result.h"


#define DEVICE_TIMER_INTERVAL 500 // ms

extern const quint32 freq_table[26];

class Device : public QObject
{
    Q_OBJECT

    Q_PROPERTY(quint8 device_id READ getDeviceId NOTIFY deviceIdChanged)
    Q_PROPERTY(QString ip_addr READ getIpAddress NOTIFY ipAddressChanged)
    Q_PROPERTY(Types::DeviceStatus device_status READ getDeviceStatus NOTIFY statusChanged)
    Q_PROPERTY(QDateTime last_update READ getLastUpdate NOTIFY lastUpdateChanged)
    Q_PROPERTY(float cur_current READ getCurVoltage NOTIFY voltageChanged)
    Q_PROPERTY(QList<Result *> results READ getResults NOTIFY resultsListChanged)
    Q_PROPERTY(quint16 cur_freq_index READ getCurFreqIndex NOTIFY curFreqIndexChanged)
    Q_PROPERTY(quint16 cur_freq READ getCurFreq NOTIFY curFreqChanged)
    Q_PROPERTY(quint16 freq_num READ getFreqNum CONSTANT)
    Q_PROPERTY(float cur_voltage READ getCurVoltage NOTIFY voltageChanged)
    Q_PROPERTY(QList<Task *> tasks READ getTasks NOTIFY tasksListChanged)

public:
    explicit Device(QObject *parent = nullptr);
    explicit Device(QObject *parent, quint8 device_id, QTcpSocket *socket, const QString &ip);
    ~Device();

    QTcpSocket *socket_ins;

    void setDeviceId(quint8 id)
    {
        device_id = id;
        emit deviceIdChanged(id);
    }
    quint8 getDeviceId() const { return device_id; }

    void setIpAddress(const QString &ip)
    {
        ip_addr = ip;
        emit ipAddressChanged(ip);
    }
    QString getIpAddress() const { return ip_addr; }

    void setDeviceStatus(Types::DeviceStatus status);
    Types::DeviceStatus getDeviceStatus() const { return device_status; }

    void setLastUpdate(const QDateTime &time)
    {
        last_update = time;
        emit lastUpdateChanged(time);
    }
    void setLastUpdate()
    {
        last_update = QDateTime::currentDateTime();
        emit lastUpdateChanged(last_update);
    }
    QDateTime getLastUpdate() const { return last_update; }

    float getCurVoltage() const { return cur_voltage; }
    void setCurVoltage(float voltage)
    {
        cur_voltage = voltage;
        emit voltageChanged(cur_voltage);
    }
    void setCurVoltage(quint16 voltage)
    {
        // 12位AD, 3.3V量程，二倍缩放
        cur_voltage = static_cast<float>(voltage) * 3.3f / 4096.0f * 2;
        emit voltageChanged(cur_voltage);
    }
    QList<Result *> getResults() const { return results; }

    void setCurFreqIndex(quint16 index)
    {
        cur_freq_index = index;
        cur_freq = freq_table[cur_freq_index];
        emit curFreqIndexChanged();
        emit curFreqChanged();
    }
    void setCurFreq(quint16 freq)
    {
        cur_freq = freq;
        emit curFreqChanged();
    }
    quint16 getCurFreqIndex() const { return cur_freq_index; }
    quint16 getCurFreq() const { return cur_freq; }
    quint16 getFreqNum() const { return sizeof(freq_table) / sizeof(freq_table[0]); }

    QList<Task *> getTasks() const { return tasks; }
    void setTask(quint64 task_id, Task *task);

    Q_INVOKABLE bool newEIS(Types::DrivingCurrent current);
    Q_INVOKABLE bool newSingle(Types::DrivingCurrent current, quint16 freq);
    void measureAt(Types::DrivingCurrent vol, quint16 freq);
    void stopMeasure();

    void onMeasureAck();
    void onStopAck();
    void onResultReceived(quint16 volt, double real, double imag);
    void onVoltageReceived(quint16 voltage);

signals:
    void deviceIdChanged(quint8 id);
    void ipAddressChanged(const QString &ip);
    void statusChanged(Types::DeviceStatus status);
    void lastUpdateChanged(const QDateTime &time);
    void voltageChanged(float voltage);
    void resultsListChanged(const QList<Result *> &results);
    void curFreqChanged();
    void curFreqIndexChanged();
    void tasksListChanged(const QList<Task *> &tasks);

private:
    int device_id;
    QString ip_addr;
    Types::DeviceStatus device_status;
    QDateTime last_update;
    QDateTime last_send_time;
    float cur_voltage;

    QList<Result *> results;

    QList<Task *> tasks;
    Types::TaskType cur_measure_type;
    QTimer task_timer;
    
    Types::DrivingCurrent cur_current;
    quint16 cur_freq;
    quint16 cur_freq_index;
    bool sendToDevice(const QByteArray &data);
    void setUnknown();

public slots:
    void runTask();
};

#endif // DEVICE_H
